home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / new_file / mintprgs / mint112s / mint112s.lzh / dosmem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-14  |  38.2 KB  |  1,495 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * GEMDOS emulation routines: these are for the GEMDOS system calls
  9.  * concerning allocating/freeing memory, including Pexec() (since
  10.  * this allocates memory) and Pterm() (since this, implicitly, frees
  11.  * it).
  12.  */
  13.  
  14. #include "mint.h"
  15.  
  16. #define DIRSEP(c) ((c) == '\\')
  17.  
  18. int procdate, proctime;    /* set when any processes are created/destroyed */
  19.  
  20. static long do_vfork P_((int));
  21.  
  22. /*
  23.  * new call for TT TOS, for the user to inform DOS of alternate memory
  24.  * FIXME: we really shouldn't trust the user so completely
  25.  * FIXME: doesn't work if memory protection is on
  26.  */
  27.  
  28. long ARGS_ON_STACK
  29. m_addalt(start, size)
  30.     long start, size;
  31. {
  32.     extern int no_mem_prot;        /* see main.c and memprot.c */
  33.  
  34.     if (!no_mem_prot) return 0;    /* pretend to succeed */
  35.     if (!add_region(alt, start, size, M_ALT))
  36.         return EINTRN;
  37.     else
  38.         return 0;
  39. }
  40.  
  41. /*
  42.  * internal routine for doing Malloc on a particular memory map
  43.  */
  44.  
  45. long
  46. _do_malloc(map, size, mode)
  47.     MMAP map;
  48.     long size;
  49.     int mode;
  50. {
  51.     virtaddr v;
  52.     MEMREGION *m;
  53.     long maxsize, mleft;
  54.  
  55.     if (size == -1L) {
  56.         maxsize = max_rsize(map, 0L);
  57.         if (curproc->maxmem) {
  58.             mleft = curproc->maxmem - memused(curproc);
  59.             if (maxsize > mleft)
  60.                 maxsize = mleft;
  61.             if (maxsize < 0)
  62.                 maxsize = 0;
  63.         }
  64.     /* make sure to round down */
  65.         return maxsize & ~MASKBITS;
  66.     }
  67.  
  68. /* special case: Malloc(0) should always return 0 */
  69.     if (size == 0)
  70.         return 0;
  71.  
  72.     if (curproc->maxmem) {        /* memory limit? */
  73.         if (size > curproc->maxmem - memused(curproc)) {
  74.             DEBUG(("malloc: memory request would exceed limit"));
  75.             return 0;
  76.         }
  77.     }
  78.  
  79.     m = get_region(map, size, mode);
  80.     if (!m) {
  81.         return 0;
  82.     }
  83.     v = attach_region(curproc, m);
  84.     if (!v) {
  85.         m->links = 0;
  86.         free_region(m);
  87.         return 0;
  88.     }
  89. /* NOTE: get_region returns a region with link count 1; since attach_region
  90.  * increments the link count, we have to remember to decrement the count
  91.  * to correct for this.
  92.  */
  93.     m->links--;
  94.     if ((mode & F_KEEP)) {    /* request for permanent memory */
  95.         m->mflags |= M_KEEP;
  96.     }
  97.     return (long)v;
  98. }
  99.  
  100. long ARGS_ON_STACK
  101. m_xalloc(size, mode)
  102.     long size;
  103.     int mode;
  104. {
  105.     long r, r1;
  106.     int protmode;
  107. #ifdef DEBUG_INFO
  108.     int origmode = mode;
  109. #endif
  110.  
  111.     TRACE(("Mxalloc(%ld,%x)",size,mode));
  112.  
  113. /*
  114.  * AKP: Hack here: if the calling process' PC is in ROM, then this is a
  115.  * Malloc call made by VDI's v_opnvwk routine.  So we change mode to
  116.  * include "super accessible."  This is temporary, until VDI catches up
  117.  * with multitasking TOS.
  118.  */
  119.  
  120.     if (((mode & F_PROTMODE) == 0) &&
  121.         (curproc->ctxt[SYSCALL].pc > 0x00e00000L) &&
  122.         (curproc->ctxt[SYSCALL].pc < 0x00efffffL)) {
  123. #ifndef MULTITOS
  124.       extern long gem_start;
  125.       if (gem_start && curproc->ctxt[SYSCALL].pc >= gem_start)
  126.         {
  127.           mode |= F_PROT_G + 0x10;
  128.           TRACE (("m_xalloc: AES special (call from ROM)"));
  129.         }
  130.       else
  131. #endif
  132.         {
  133.         mode |= (F_PROT_S + 0x10) | F_KEEP;
  134.         TRACE(("m_xalloc: VDI special (call from ROM)"));
  135.         }
  136.     }
  137. /*
  138.  * If the mode argument comes in a zero, then set it to the default
  139.  * value from prgflags.  Otherwise subtract one from it to bring it
  140.  * into line with the actual argument to alloc_region.
  141.  */
  142.     protmode = (mode & F_PROTMODE) >> F_PROTSHIFT;
  143.  
  144.     if (protmode == 0) {
  145.         protmode = (curproc->memflags & F_PROTMODE) >> F_PROTSHIFT;
  146.     }
  147.     else --protmode;
  148.  
  149.     if (protmode > PROT_MAX_MODE) {
  150.         DEBUG(("Mxalloc: invalid protection mode changed to private"));
  151.         protmode = PROT_P;
  152.     }
  153.  
  154. #if 0
  155. /* I'm very suspicious of the 0x08 flag; I can't see how it could
  156.  * work as the comment below seems to indicate -- ERS
  157.  */
  158.  
  159. /*
  160.  * if the mode argument has the 0x08 bit set then you're trying to change
  161.  * the protection mode of a block you already own. "size" is really its
  162.  * base address. (new as of 2/6/92)
  163.  */
  164.     if (mode & 0x08) change_prot_status(curproc,size,protmode);
  165. #endif
  166.  
  167.     /*
  168.      * Copy the F_KEEP attribute into protmode.  We didn't do that
  169.      * before now because change_prot_status don't want to see no
  170.      * steenking nofree attributes.
  171.      */
  172.  
  173.     protmode |= (mode & F_KEEP);
  174.  
  175.     /* mask off all but the ST/alternative RAM bits before further use */
  176.     mode &= 3;
  177.  
  178.     if (mode == 0) {
  179.         r = _do_malloc(core, size, protmode);
  180.         goto ret;
  181.     }
  182.     else if (mode == 1) {
  183.         r = _do_malloc(alt, size, protmode);
  184.         goto ret;
  185.     }
  186.     else if (size == -1) {
  187.         /* modes 2 and 3 are the same for for size -1 */
  188.         r = _do_malloc(core, -1L, PROT_P);
  189.         r1 = _do_malloc(alt, -1L, PROT_P);
  190.         if (r1 > r) r = r1;
  191.         goto ret;
  192.     }
  193.     else if (mode == 2) {
  194.         r = _do_malloc(core, size, protmode);
  195.         if (r == 0) r = _do_malloc(alt, size, protmode);
  196.         goto ret;
  197.     }
  198.     else /* if (mode == 3) */ {
  199.         r = _do_malloc(alt, size, protmode);
  200.         if (r == 0) r = _do_malloc(core, size, protmode);
  201.         goto ret;
  202.     }
  203. ret:
  204.     if (r == 0) {
  205.         DEBUG(("m_xalloc(%lx,%x) returns 0",size,origmode));
  206.     } else {
  207.         TRACE(("m_xalloc(%lx,%x) returns %lx",size,origmode,r));
  208.     }
  209.     return r;
  210. }
  211.  
  212. long ARGS_ON_STACK
  213. m_alloc(size)
  214.     long size;
  215. {
  216.     long r;
  217.  
  218.     TRACE(("Malloc(%lx)", size));
  219.     if (curproc->memflags & F_ALTALLOC)
  220.         r = m_xalloc(size, 3);
  221.     else
  222.         r = m_xalloc(size, 0);
  223.     TRACE(("Malloc: returning %lx", r));
  224.     return r;
  225. }
  226.  
  227. long ARGS_ON_STACK
  228. m_free(block)
  229.     virtaddr block;
  230. {
  231.     MEMREGION *m;
  232.     int i;
  233.  
  234.     TRACE(("Mfree(%lx)", block));
  235.     if (!block) {
  236.         DEBUG(("Mfree: null pointer"));
  237.         return EIMBA;
  238.     }
  239.  
  240. /* search backwards so that most recently allocated incarnations of
  241.    shared memory blocks are freed first (this doesn't matter very often)
  242.  */
  243.  
  244.     for (i = curproc->num_reg - 1; i >= 0; i--) {
  245.         if (curproc->addr[i] == block) {
  246.             m = curproc->mem[i];
  247.             assert(m != NULL);
  248.             assert(m->loc == (long)block);
  249.             curproc->mem[i] = 0;
  250.             curproc->addr[i] = 0;
  251.             m->links--;
  252.             if (m->links == 0) {
  253.                 free_region(m);
  254.             }
  255.             return 0;
  256.         }
  257.     }
  258.  
  259. /* hmmm... if we didn't find the region, perhaps it's a global
  260.  * one (with the M_KEEP flag set) belonging to a process that
  261.  * terminated
  262.  */
  263.     for (i = rootproc->num_reg - 1; i >= 0; i--) {
  264.         if (rootproc->addr[i] == block) {
  265.             m = rootproc->mem[i];
  266.             assert(m != NULL);
  267.             assert(m->loc == (long)block);
  268.             if (!(m->mflags & M_KEEP))
  269.                 continue;
  270.             TRACE(("Freeing M_KEPT memory"));
  271.             rootproc->mem[i] = 0;
  272.             rootproc->addr[i] = 0;
  273.             m->links--;
  274.             if (m->links == 0) {
  275.                 free_region(m);
  276.             }
  277.             return 0;
  278.         }
  279.     }
  280.  
  281.  
  282.     DEBUG(("Mfree: bad address %lx", block));
  283.     return EIMBA;
  284. }
  285.  
  286. long ARGS_ON_STACK
  287. m_shrink(dummy, block, size)
  288.     int dummy;
  289.     virtaddr block;
  290.     long size;
  291. {
  292.     MEMREGION *m;
  293.     int i;
  294.  
  295.     UNUSED(dummy);
  296.     TRACE(("Mshrink: %lx to %ld", block, size));
  297.     if (!block) {
  298.         DEBUG(("Mshrink: null pointer"));
  299.         return EIMBA;
  300.     }
  301.  
  302.     for (i = 0; i < curproc->num_reg; i++) {
  303.         if (curproc->addr[i] == block) {
  304.             m = curproc->mem[i];
  305.             assert(m != NULL);
  306.             assert(m->loc == (long)block);
  307.             return shrink_region(m, size);
  308.         }
  309.     }
  310.     DEBUG(("Mshrink: bad address (%lx)", block));
  311.     return EIMBA;
  312. }
  313.  
  314. long ARGS_ON_STACK
  315. p_exec(mode, ptr1, ptr2, ptr3)
  316.     int mode;
  317.     void *ptr1, *ptr2, *ptr3;
  318. {
  319.     MEMREGION *base,
  320.         *env = 0;    /* assignment suppresses spurious warning */
  321.     MEMREGION *text = 0;    /* for shared text regions */
  322.     PROC *p;
  323.     long r, flags = 0;
  324.     int i;
  325.     char mkbase = 0, mkload = 0, mkgo = 0, mkwait = 0, mkfree = 0;
  326.     char overlay = 0;
  327.     char thread = 0;
  328.     char ptrace;
  329.     char mkname = 0, *newname, *lastslash;
  330.     char localname[PNAMSIZ+1];
  331.     XATTR xattr;
  332.     int newpid;
  333. #ifndef MULTITOS
  334.     extern BASEPAGE *gem_base;
  335. #endif
  336.  
  337. #ifdef DEBUG_INFO
  338. /* tfmt and tail_offs are used for debugging only */
  339.     const char *tfmt = "Pexec(%d,%s,\"%s\",%lx)";
  340.     int tail_offs = 1;
  341. #endif
  342.  
  343. /* the high bit of mode controls process tracing */
  344.     switch(mode & 0x7fff) {
  345.     case 0:
  346.         mkwait = 1;        /* fall through */
  347.     case 100:
  348.         mkload = mkgo = mkfree = 1;
  349.         mkname = 1;
  350.         break;
  351.     case 200:            /* overlay current process */
  352.         mkload = mkgo = 1;
  353.         overlay = mkname = 1;
  354.         break;
  355.     case 3:
  356.         mkload = 1;
  357.         break;
  358.     case 6:
  359.         mkfree = 1;
  360.         /* fall through */
  361.     case 4:
  362.         mkwait = mkgo = 1;
  363.         thread = (mode == 4);
  364. #ifdef DEBUG_INFO
  365.         tfmt = "Pexec(%d,%lx,BP:%lx,%lx)";
  366.         tail_offs = 0;
  367. #endif
  368.         break;
  369.     case 106:
  370.         mkfree = 1;        /* fall through */
  371.     case 104:
  372.         thread = (mode == 104);
  373.         mkgo = 1;
  374.         mkname = (ptr1 != 0);
  375. #ifdef DEBUG_INFO
  376.         tfmt = "Pexec(%d,%s,BP:%lx,%lx)";
  377.         tail_offs = 0;
  378. #endif
  379.         break;
  380.     case 206:
  381. #if 0
  382.     /* mkfree has no effect when overlay is set, since
  383.      * in this case the "parent" and "child" are the same
  384.      * process; since the "child" will run in memory that the
  385.      * "parent" allocated, we don't want that memory freed!
  386.      */
  387.         mkfree = 1;
  388. #endif
  389.         /* fall through */
  390.     case 204:
  391.         mkgo = overlay = 1;
  392.         mkname = (ptr1 != 0);
  393. #ifdef DEBUG_INFO
  394.         tfmt = "Pexec(%d,%s,BP:%lx,%lx)";
  395.         tail_offs = 0;
  396. #endif
  397.         break;
  398.     case 7:
  399.         flags = (long)ptr1;    /* set program flags */
  400.         if (((flags & F_PROTMODE) >> F_PROTSHIFT) > PROT_MAX_MODE) {
  401.             DEBUG (("Pexec: invalid protection mode changed to private"));
  402.             flags = (flags & ~F_PROTMODE) | F_PROT_P;
  403.         }
  404. #ifndef MULTITOS
  405.         if ((flags & F_PROTMODE) == 0 && curproc->base == gem_base)
  406.           {
  407.             flags |= F_PROT_G;
  408.             TRACE (("p_exec: AES special"));
  409.           }
  410. #endif
  411.                     /* and fall through */
  412.     case 5:
  413.         mkbase = 1;
  414. #ifdef DEBUG_INFO
  415.         tfmt = "Pexec(%d,%lx,%s,%lx)";
  416.         tail_offs = 0;
  417. #endif
  418.         break;
  419.     default:
  420.         DEBUG(("Pexec(%d,%lx,%lx,%lx): bad mode",mode,ptr1,ptr2,ptr3));
  421.         return EINVFN;
  422.     }
  423.  
  424.     TRACE((tfmt,mode,ptr1,(char *)ptr2+tail_offs,ptr3));
  425.  
  426. /* Pexec with mode 0x8000 indicates tracing should be active */
  427.     ptrace = (!mkwait && (mode & 0x8000));
  428.  
  429. /* in most cases, we'll want a process struct to exist,
  430.  * so make sure one is around. Note that we must be
  431.  * careful to free it later!
  432.  */
  433.  
  434. TRACE(("Checking for memory for new PROC structure"));
  435.     p = 0;
  436.     if (!overlay) {
  437.         p = new_proc();
  438.         if (!p) {
  439.             DEBUG(("Pexec: couldn't get a PROC struct"));
  440.             return ENSMEM;
  441.         }
  442.     }
  443.  
  444. TRACE(("creating environment"));
  445.  
  446.     if (mkload || mkbase) {
  447.         env = create_env((char *)ptr3, flags);
  448.         if (!env) {
  449.             DEBUG(("Pexec: unable to create environment"));
  450.             if (p) dispose_proc(p);
  451.             return ENSMEM;
  452.         }
  453.     }
  454.  
  455. TRACE(("creating base page"));
  456.  
  457.     if (mkbase) {
  458.         base = create_base((char *)ptr2, env, flags, 0L, 0L, 0L, 0L, 0L, 0L);
  459.         if (!base) {
  460.             DEBUG(("Pexec: unable to create basepage"));
  461.             detach_region(curproc, env);
  462.             if (p) dispose_proc(p);
  463.             return ENSMEM;
  464.         }
  465. TRACELOW(("Pexec: basepage region(%lx) is %ld bytes at %lx", base, base->len, base->loc));
  466.     }
  467.     else if (mkload) {
  468.         char cbuf[128], *tail = ptr2;
  469.         if (overlay) {
  470.             static char fbuf[PATH_MAX];
  471.             cbuf[127] = 0;
  472.             ptr1 = strncpy (fbuf, ptr1, PATH_MAX-2);
  473.             tail = strncpy (cbuf, ptr2, 127);
  474.         }
  475. #if 0
  476.         base = load_region((char *)ptr1, env, (char *)tail,
  477.             &xattr, &text, &flags, 0);
  478. #else
  479.         base = load_region((char *)ptr1, env, (char *)tail,
  480.             &xattr, &text, &flags, overlay);
  481. #endif
  482.         if (!base) {
  483.             DEBUG(("Pexec: load_region failed"));
  484.             detach_region(curproc, env);
  485.             if (p) dispose_proc(p);
  486.             return mint_errno;
  487.         }
  488. TRACE(("Pexec: basepage region(%lx) is %ld bytes at %lx", base, base->len, base->loc));
  489.     }
  490.     else {    /* mode == 4,6,104,106,204, or 206 -- just go */
  491.         base = addr2mem((virtaddr)ptr2);
  492.         if (base)
  493.             env = addr2mem(*(void **)(base->loc + 0x2c));
  494.         else
  495.             env = 0;
  496.         if (!env) {
  497.             DEBUG(("Pexec: memory not owned by parent"));
  498.             if (p) dispose_proc(p);
  499.             return EIMBA;
  500.         }
  501. #if 0
  502.       /* make sure that the PC we are about to use is in a region which is
  503.        * attached to the process; this is most commonly a problem for
  504.        * shared text segment programs.
  505.        * BUG: we should verify that the PC is in a region to which the
  506.        * child process should legitimately have access.
  507.        */
  508.               text = addr2region(((BASEPAGE *)base->loc)->p_tbase);
  509.               if (text == base) {
  510.               /* text segment is part of base region */
  511.                       text = NULL;
  512.               }
  513. #endif
  514.     }
  515.  
  516. /* make a local copy of the name, in case we are overlaying the current
  517.  * process
  518.  */
  519.     if (mkname) {
  520.         lastslash = 0;
  521.         newname = ptr1;
  522.         while (*newname) {
  523.             if (*newname == '\\' || *newname == '/')
  524.                 lastslash = newname;
  525.             ++newname;
  526.         }
  527.         if (!lastslash)
  528.             lastslash = ptr1;
  529.         else
  530.             lastslash++;
  531.  
  532.         i = 0; newname = localname;
  533.         while (i++ < PNAMSIZ) {
  534.             if (*lastslash == '.' || *lastslash == 0) {
  535.                 *newname = 0; break;
  536.             }
  537.             else
  538.                 *newname++ = *lastslash++;
  539.         }
  540.         *newname = 0;
  541.     }
  542.  
  543.     if (mkload || mkbase) {
  544.         /*
  545.          * Now that the file's loaded, flags is set to the prgflags
  546.          * for the file.  In the case of mkbase it's been right all along.
  547.          * Here's where we change the protection on the environment to
  548.          * match those flags.
  549.          */
  550.         mark_region(env,(short)((flags & F_PROTMODE) >> F_PROTSHIFT));
  551.     }
  552.  
  553.     if (p) {
  554.     /* free the PROC struct so fork_proc will succeed */
  555.     /* FIXME: it would be much better to pass the PROC as a parameter
  556.      * to fork_proc!!
  557.      */
  558.         dispose_proc(p);
  559.         p = 0;
  560.     }
  561.  
  562.     if (mkgo) {
  563.         BASEPAGE *b;
  564.  
  565.     /* tell the child who the parent was */
  566.         b = (BASEPAGE *)base->loc;
  567.  
  568.         if (overlay) {
  569.             b->p_parent = curproc->base->p_parent;
  570.             p = curproc;
  571.         /* make sure that exec_region doesn't free the base and env */
  572.             base->links++;
  573.             env->links++;
  574.             if (text) text->links++;
  575.         }
  576.         else {
  577.             b->p_parent = curproc->base;
  578.             p = fork_proc();
  579.         }
  580.         if (!p) {
  581.             if (mkbase) {
  582.                 detach_region(curproc, base);
  583.                 detach_region(curproc, env);
  584.                 if (text) detach_region(curproc, text);
  585.             }
  586.             return mint_errno;
  587.         }
  588.  
  589.     /* jr: add Pexec information to PROC struct */
  590.         strncpy(p->cmdlin, b->p_cmdlin, 128);
  591.         p->fname[0] = 0;
  592.         if (mkload) {
  593.             char tmp[PATH_MAX];
  594.             char *source = ptr1;
  595.             tmp[1] = ':';
  596.             if (source[1] == ':') {
  597.                 tmp[0] = source[0];
  598.                 source += 2;
  599.             } else
  600.                 tmp[0] = 'A' + curproc->curdrv;
  601.             if (DIRSEP(source[0]))    /* absolute path? */
  602.             {
  603.                 strncpy (&tmp[2], &source[0], PATH_MAX-2);
  604.                 strcpy (p->fname, tmp);
  605.             } else {
  606.                 if (! d_getcwd (&tmp[2], tmp[0] - 'A' + 1, PATH_MAX - 2))
  607.                     ksprintf (p->fname, "%s\\%s", tmp, source);
  608.             }
  609.         }
  610.  
  611.         if (ptrace)
  612.             p->ptracer = pid2proc(p->ppid);
  613.  
  614.     /* Even though the file system won't allow unauthorized access
  615.      * to setuid/setgid programs, it's better to err on the side of
  616.      * caution and forbid them to be traced (since the parent can arrange
  617.      * to share the child's address space, not all accesses need to
  618.      * go through the file system.)
  619.      */
  620.         if (mkload && mkgo && !p->ptracer) {    /* setuid/setgid is OK */
  621.             if (xattr.mode & S_ISUID)
  622.                 p->euid = xattr.uid;
  623.             if (xattr.mode & S_ISGID)
  624.                 p->egid = xattr.gid;
  625.         }
  626.     /* exec_region frees the memory attached to p; that's always what
  627.      * we want, since fork_proc duplicates the memory, and since
  628.      * if we didn't call fork_proc then we're overlaying.
  629.      * NOTE: after this call, we may not be able to access the
  630.      * original address space that the Pexec was taking place in
  631.      * (if this is an overlaid Pexec, we just freed that memory).
  632.      */
  633.         (void)exec_region(p, base, thread);
  634.         attach_region(p, env);
  635.         attach_region(p, base);
  636.         if (text) attach_region(p, text);
  637.  
  638.         if (mkname) {
  639.     /* interesting coincidence -- if a process needs a name, it usually
  640.      * needs to have its domain reset to DOM_TOS. Doing it this way
  641.      * (instead of doing it in exec_region) means that Pexec(4,...)
  642.      * can be used to create new threads of execution which retain
  643.      * the same domain.
  644.      */
  645.             if (!thread)
  646.                 p->domain = DOM_TOS;
  647.  
  648.     /* put in the new process name we saved above */
  649.             strcpy(p->name, localname);
  650.         }
  651.  
  652.     /* turn on tracing for the new process */
  653.         if (p->ptracer)
  654.             p->ctxt[CURRENT].ptrace = 1;
  655.  
  656.     /* set the time/date stamp of u:\proc */
  657.         proctime = timestamp;
  658.         procdate = datestamp;
  659.  
  660.         if (overlay) {
  661.             /* correct for temporary increase in links (see above) */
  662.             base->links--;
  663.             env->links--;
  664.             if (text) text->links--;
  665.             /* let our parent run, if it Vfork'd() */
  666.             if ( (p = pid2proc(curproc->ppid)) != 0 ) {
  667.                 if (p->wait_q == WAIT_Q && 
  668.                     p->wait_cond == (long)curproc) {
  669.                     short sr = spl7();
  670.                     rm_q(WAIT_Q, p);
  671.                     add_q(READY_Q, p);
  672.                     spl(sr);
  673.                 }
  674.             }
  675.  
  676.         /* OK, let's run our new code */
  677.         /* we guarantee ourselves at least 3 timeslices to do an Mshrink */
  678.             assert(curproc->magic == CTXT_MAGIC);
  679.             fresh_slices(3);
  680.             leave_kernel();
  681.             change_context(&(curproc->ctxt[CURRENT]));
  682.         }
  683.         else {
  684.     /* we want this process to run ASAP */
  685.     /* so we temporarily give it high priority and put it first on the
  686.      * run queue
  687.      */
  688.             run_next(p, 3);
  689.         }
  690.     }
  691.  
  692.     if (mkfree) {
  693.         detach_region(curproc, base);
  694.         detach_region(curproc, env);
  695.         if (text) detach_region(curproc, text);
  696.     }
  697.  
  698.     if (mkwait) {
  699.         long oldsigint, oldsigquit;
  700.  
  701.         oldsigint = curproc->sighandle[SIGINT];
  702.         oldsigquit = curproc->sighandle[SIGQUIT];
  703.         curproc->sighandle[SIGINT] =
  704.              curproc->sighandle[SIGQUIT] = SIG_IGN;
  705.  
  706.         newpid = p->pid;
  707.         for(;;) {
  708.             r = p_wait3(0, (long *)0);
  709.             if (r < 0) {
  710.                 ALERT("p_exec: wait error");
  711.                 return EINTRN;
  712.             }
  713.             if ( newpid == ((r&0xffff0000L) >> 16) ) {
  714.                 TRACE(("leaving Pexec; child return code %ld", r));
  715.                 r = r & 0x0000ffffL;
  716.                 break;
  717.             }
  718.             if (curproc->pid)
  719.                 DEBUG(("Pexec: wrong child found"));
  720.         }
  721.         curproc->sighandle[SIGINT] = oldsigint;
  722.         curproc->sighandle[SIGQUIT] = oldsigquit;
  723.         return r;
  724.     }
  725.     else if (mkgo) {
  726.     /* warning: after the yield() the "p" structure may not exist any more
  727.      * (if the child exits right away)
  728.      */
  729.         newpid = p->pid;
  730.         yield();    /* let the new process run */
  731.         return newpid;
  732.     } else {
  733.         /* guarantee ourselves at least 3 timeslices to do an Mshrink */
  734.         fresh_slices(3);
  735.         TRACE(("leaving Pexec with basepage address %lx", base->loc));
  736.         return base->loc;
  737.     }
  738. }
  739.  
  740. /*
  741.  * terminate a process, with return code "code". If que == ZOMBIE_Q, free
  742.  * all resources attached to the child; if que == TSR_Q, free everything
  743.  * but memory.
  744.  * NOTE: terminate() should be called only when the process is to be
  745.  * "terminated with extreme prejuidice". Most times, p_term or p_termres
  746.  * are the functions to use, since they allow the user to do some cleaning
  747.  * up, etc.
  748.  */
  749.  
  750. long
  751. terminate(code, que)
  752.     int code, que;
  753. {
  754.     extern PROC *dlockproc[];    /* in dosdir.c */
  755.     PROC *p;
  756.     FILEPTR *fp;
  757.     MEMREGION *m;
  758.     MEMREGION **hold_mem;
  759.     virtaddr *hold_addr;
  760.     int  i, wakemint = 0;
  761.     DIR *dirh, *nexth;
  762.     extern short bconbsiz;    /* in bios.c */
  763.  
  764.     if (bconbsiz)
  765.         (void) bflush();
  766.  
  767.     assert(que == ZOMBIE_Q || que == TSR_Q);
  768.  
  769.     if (curproc->pid == 0) {
  770.         FATAL("attempt to terminate MiNT");
  771.     }
  772.  
  773. /* cancel all user-specified interrupt signals */
  774.     cancelsigintrs();
  775. /* cancel all pending timeouts for this process */
  776.     cancelalltimeouts();
  777. /* cancel alarm clock */
  778.     curproc->alarmtim = 0;
  779.  
  780. /* release any drives locked by Dlock */
  781.     for(i = 0; i < NUM_DRIVES; i++) {
  782.         if (dlockproc[i] == curproc) {
  783.             dlockproc[i] = 0;
  784.             changedrv(i);
  785.         }
  786.     }
  787.  
  788. #if 0
  789. /* release the controlling terminal, if we're a process group leader */
  790.     fp = curproc->handle[-1];
  791.     if (fp && is_terminal(fp) && curproc->pgrp == curproc->pid) {
  792.         struct tty *tty = (struct tty *)fp->devinfo;
  793.         if (curproc->pgrp == tty->pgrp)
  794.             tty->pgrp = 0;
  795.     }
  796. #else
  797. #if 0
  798. /* release the controlling terminal, if we're the last member of this pgroup */
  799.     fp = curproc->control;
  800.     if (fp && is_terminal(fp)) {
  801.         struct tty *tty = (struct tty *)fp->devinfo;
  802.         int pgrp = curproc->pgrp;
  803.  
  804.         if (pgrp == tty->pgrp) {
  805.             PROC *p;
  806.             FILEPTR *pfp;
  807.  
  808.             if (tty->use_cnt > 1) {
  809.                 for (p = proclist; p; p = p->gl_next) {
  810.                     if (p->pgrp == pgrp && p != curproc &&
  811.                         (0 != (pfp = p->control)) &&
  812.                         pfp->fc.index == fp->fc.index &&
  813.                         pfp->fc.dev == fp->fc.dev)
  814.                         goto found;
  815.                 }
  816.             } else {
  817.                 for (p = proclist; p; p = p->gl_next) {
  818.                     if (p->pgrp == pgrp && p != curproc &&
  819.                         p->control == fp)
  820.                         goto found;
  821.                 }
  822.             }
  823.             tty->pgrp = 0;
  824.         }
  825. found:
  826.         ;
  827.     }
  828. #endif
  829. #endif
  830.     /* close all files */
  831.     for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  832.         if ((fp = curproc->handle[i]) != 0)
  833.             do_close(fp);
  834.         curproc->handle[i] = 0;
  835.     }
  836.     /* close any unresolved Fsfirst/Fsnext directory searches */
  837.     for (i = 0; i < NUM_SEARCH; i++) {
  838.         if (curproc->srchdta[i]) {
  839.             DIR *dirh = &curproc->srchdir[i];
  840.             (*dirh->fc.fs->closedir)(dirh);
  841.             release_cookie(&dirh->fc);
  842.             dirh->fc.fs = 0;
  843.         }
  844.     }
  845.  
  846. /* close pending opendir/readdir searches */
  847.     for (dirh = curproc->searches; dirh; ) {
  848.         if (dirh->fc.fs) {
  849.             (*dirh->fc.fs->closedir)(dirh);
  850.             release_cookie(&dirh->fc);
  851.         }
  852.         nexth = dirh->next;
  853.         kfree(dirh);
  854.         dirh = nexth;
  855.     }
  856.  
  857. /* release the directory cookies held by the process */
  858.     for (i = 0; i < NUM_DRIVES; i++) {
  859.         release_cookie(&curproc->curdir[i]);
  860.         curproc->curdir[i].fs = 0;
  861.         release_cookie(&curproc->root[i]);
  862.         curproc->root[i].fs = 0;
  863.     }
  864.  
  865. /* release all semaphores owned by this process */
  866.     free_semaphores(curproc->pid);
  867.  
  868. /* free all memory */
  869. /* if mflags & M_KEEP then attach it to process 0 */
  870.     if (que == ZOMBIE_Q) {
  871.         for (i = curproc->num_reg - 1; i >=0; i--) {
  872.             m = curproc->mem[i];
  873.             curproc->mem[i] = 0; curproc->addr[i] = 0;
  874.             if (m) {
  875.         /* don't free specially allocated memory */
  876.                 if ((m->mflags & M_KEEP) && (m->links <= 1)) {
  877.                     if (curproc != rootproc)
  878.                         attach_region(rootproc, m);
  879.                 }
  880. /* Leave shared text regions in memory, get_region will reclaim them if
  881.    memory runs low. Assume that we will never have 65535 processes
  882.    using a particular memory region. */
  883.                 m->links--;
  884.                 if (m->links == 0) {
  885.                     if (m->mflags & M_SHTEXT_T)
  886.                         m->links = 0xffff;
  887.                     else
  888.                         free_region(m);
  889.                 }
  890.             }
  891.         }
  892.  
  893.         /*
  894.          * mark the mem & addr arrays as void so the memory
  895.          * protection code won't try to walk them. Do this before
  896.          * freeing them so we don't try to walk them when marking
  897.          * those pages themselves as free!
  898.          *
  899.          * Note: when a process terminates, the MMU root pointer
  900.          * still points to that process' page table, until the next
  901.          * process is dispatched.  This is OK, since the process'
  902.          * page table is in system memory, and it isn't going to be
  903.          * freed.  It is going to wind up on the free process list,
  904.          * though, after dispose_proc. This might be Not A Good
  905.          * Thing.
  906.          */
  907.  
  908.         hold_addr = curproc->addr;
  909.         hold_mem = curproc->mem;
  910.  
  911.         curproc->mem = NULL;
  912.         curproc->addr = NULL;
  913.         curproc->num_reg = 0;
  914.  
  915.         kfree(hold_addr);
  916.         kfree(hold_mem);
  917.     }
  918. /*    else
  919.          make TSR process non-swappable */
  920.  
  921. /*
  922.  * make sure that any open files that refer to this process are
  923.  * closed
  924.  */
  925.     changedrv(PROC_RDEV_BASE | curproc->pid);
  926.  
  927. /* find our parent (if parent not found, then use process 0 as parent
  928.  * since that process is constantly in a wait loop)
  929.  */
  930.  
  931.     p = pid2proc(curproc->ppid);
  932.     if (!p) {
  933.         TRACE(("terminate: parent not found"));
  934.         p = pid2proc(0);
  935.     }
  936.  
  937. /* NOTE: normally just post_sig is sufficient for sending a signal; but
  938.  * in this particular case, we have to worry about processes that are
  939.  * blocking all signals because they Vfork'd and are waiting for us to
  940.  * finish (which is indicated by a wait_cond matching our PROC
  941.  * structure), and also processes that are ignoring SIGCHLD but are
  942.  * waiting for us.
  943.  */
  944.     if (p->wait_q == WAIT_Q && 
  945.         (p->wait_cond == (long)curproc || p->wait_cond == (long)p_waitpid) ) {
  946.         short sr = spl7();
  947.         TRACE(("terminate: waking up parent"));
  948.         rm_q(WAIT_Q, p);
  949.         add_q(READY_Q, p);
  950.         spl(sr);
  951.     }
  952.     if (curproc->ptracer && curproc->ptracer != p) {
  953.         /* BUG: should we ensure curproc->ptracer is awake ? */
  954.         post_sig(curproc->ptracer, SIGCHLD);    /* tell tracing process */
  955.     }
  956.     post_sig(p, SIGCHLD);        /* inform of process termination */
  957.  
  958. /* find our children, and orphan them
  959.  * also, check for processes we were tracing, and
  960.  * cancel the trace
  961.  */
  962.     i = curproc->pid;
  963.     for (p = proclist; p; p = p->gl_next) {
  964.         if (p->ppid == i) {
  965.             p->ppid = 0;    /* have the system adopt it */
  966.             if (p->wait_q == ZOMBIE_Q) 
  967.                 wakemint = 1;    /* we need to wake proc. 0 */
  968.         }
  969.         if (p->ptracer == curproc) {
  970.             p->ptracer = 0;
  971. /*
  972.  * `FEATURE': we terminate traced processes when the tracer terminates.
  973.  * It might plausibly be argued that it would be better to let them
  974.  * continue, to let some (new) tracer take them over. On the other hand,
  975.  * if the tracer terminated normally, it should have used Fcntl(PTRACESFLAGS)
  976.  * to reset the trace nicely, so something must be wrong for us to have
  977.  * reached here.
  978.  */
  979.             post_sig(p, SIGTERM);    /* arrange for termination */
  980.         }
  981.     }
  982.  
  983.     if (wakemint) {
  984.         p = rootproc;        /* pid 0 */
  985.         if (p->wait_q == WAIT_Q) {
  986.             short sr = spl7();
  987.             rm_q(WAIT_Q, p);
  988.             add_q(READY_Q, p);
  989.             spl(sr);
  990.         }
  991.     }
  992.  
  993. /* this makes sure that our children are inherited by the system;
  994.  * plus, it may help avoid problems if somehow a signal gets
  995.  * through to us
  996.  */
  997.     for(i = 0; i < NSIG; i++)
  998.         curproc->sighandle[i] = SIG_IGN;
  999.  
  1000. /* finally, reset the time/date stamp for u:\proc */
  1001.     proctime = timestamp;
  1002.     procdate = datestamp;
  1003.  
  1004.     sleep(que, (long)(unsigned)code);
  1005.  
  1006. /* we shouldn't ever get here */
  1007.     FATAL("terminate: sleep woke up when it shouldn't have");
  1008.     return 0;
  1009. }
  1010.  
  1011. /*
  1012.  * TOS process termination entry points:
  1013.  * p_term terminates the process, freeing its memory
  1014.  * p_termres lets the process hang around resident in memory, after
  1015.  * shrinking its transient program area to "save" bytes
  1016.  */
  1017.  
  1018. long ARGS_ON_STACK
  1019. p_term(code)
  1020.     int code;
  1021. {
  1022.     CONTEXT *syscall;
  1023.  
  1024.     TRACE(("Pterm(%d)", code));
  1025. /* call the process termination vector */
  1026.     syscall = &curproc->ctxt[SYSCALL];
  1027.  
  1028.     if (syscall->term_vec != (long)rts) {
  1029.         TRACE(("term_vec: user has something to do"));
  1030. /*
  1031.  * we handle the termination vector just like Supexec(), by
  1032.  * sending signal 0 to the process. See supexec() in xbios.c for details.
  1033.  * Note that we _always_ want to unwind the signal stack, and setting
  1034.  * bit 1 of curproc->sigmask tells handle_sig to do that -- see signal.c.
  1035.  */
  1036.         curproc->sigmask |= 1L;
  1037.         (void)supexec((Func)syscall->term_vec, 0L, 0L, 0L, 0L, 
  1038.                 (long)code);
  1039. /*
  1040.  * if we arrive here, continue with the termination...
  1041.  */
  1042.     }
  1043.     return terminate(code, ZOMBIE_Q);
  1044. }
  1045.  
  1046. long ARGS_ON_STACK
  1047. p_term0()
  1048. {
  1049.     return p_term(0);
  1050. }
  1051.  
  1052. long ARGS_ON_STACK
  1053. p_termres(save, code)
  1054.     long save;
  1055.     int code;
  1056. {
  1057.     MEMREGION *m;
  1058.     int i;
  1059.  
  1060.     TRACE(("Ptermres(%ld, %d)", save, code));
  1061.     m = curproc->mem[1];    /* should be the basepage (0 is env.) */
  1062.     if (m) {
  1063.         (void)shrink_region(m, save);
  1064.     }
  1065. /*
  1066.  * make all of the TSR's private memory globally accessible;
  1067.  * this means that more TSR's will "do the right thing"
  1068.  * without having to have prgflags set.
  1069.  */
  1070.     for (i = 0; i < curproc->num_reg; i++) {
  1071.         m = curproc->mem[i];
  1072.         if (m && m->links == 1) {    /* only the TSR is owner */
  1073.             if (get_prot_mode(m) == PROT_P) {
  1074.                 mark_region(m, PROT_G);
  1075.             }
  1076.         }
  1077.     }
  1078.     return terminate(code, TSR_Q);
  1079. }
  1080.  
  1081. /*
  1082.  * routine for waiting for children to die. Return has the pid of the
  1083.  * found child in the high word, and the child's exit code in
  1084.  * the low word. If no children exist, return "File Not Found".
  1085.  * If (nohang & 1) is nonzero, then return a 0 immediately if we have
  1086.  * no dead children but some living ones that we still have to wait
  1087.  * for. If (nohang & 2) is nonzero, then we return any stopped
  1088.  * children; otherwise, only children that have exited or are stopped
  1089.  * due to a trace trap are returned.
  1090.  * If "rusage" is non-zero and a child is found, put the child's
  1091.  * resource usage into it (currently only the user and system time are
  1092.  * sent back).
  1093.  * The pid argument specifies a set of child processes for which status
  1094.  * is requested:
  1095.  *     If pid is equal to -1, status is requested for any child process.
  1096.  *
  1097.  *    If pid is greater than zero, it specifies the process ID of a
  1098.  *    single child process for which status is requested.
  1099.  *
  1100.  *    If pid is equal to zero, status is requested for any child
  1101.  *    process whose process group ID is equal to that of the calling
  1102.  *    process.
  1103.  *
  1104.  *    If pid is less than -1, status is requested for any child process
  1105.  *    whose process group ID is equal to the absolute value of pid.
  1106.  *
  1107.  * Note this call is a real standard crosser... POSIX.1 doesn't have the
  1108.  * rusage stuff, BSD doesn't have the pid stuff; both are useful, so why
  1109.  * not have it all!
  1110.  */
  1111.  
  1112. long ARGS_ON_STACK
  1113. p_waitpid(pid, nohang, rusage)
  1114.     int pid;
  1115.     int nohang;
  1116.     long *rusage;
  1117. {
  1118.     long r;
  1119.     PROC *p, *q;
  1120.     int ourpid;
  1121.     int found;
  1122.  
  1123.     TRACE(("Pwaitpid(%d, %d, %lx)", pid, nohang, rusage));
  1124.     ourpid = curproc->pid;
  1125.  
  1126. /* if there are terminated children, clean up and return their info;
  1127.  * if there are children, but still running, wait for them;
  1128.  * if there are no children, return an error
  1129.  */
  1130.  
  1131.     do {
  1132. /* look for any children */
  1133.         found = 0;
  1134.         for (p = proclist; p; p = p->gl_next) {
  1135.             if ((p->ppid == ourpid || p->ptracer == curproc) &&
  1136.                 (pid == -1 ||
  1137.                 (pid > 0 && pid == p->pid) ||
  1138.                 (pid == 0 && p->pgrp == ourpid) ||
  1139.                 (pid < -1 && p->pgrp == -pid))) {
  1140.                 found++;
  1141.                 if (p->wait_q == ZOMBIE_Q || p->wait_q == TSR_Q)
  1142.                     break;
  1143.  
  1144. /* p->wait_cond == 0 if a stopped process has already been waited for */
  1145.                 if (p->wait_q == STOP_Q && p->wait_cond) {
  1146.                     if ((nohang & 2) ||
  1147.                     ((p->wait_cond&0x1f00) == (SIGTRAP<<8)))
  1148.                         break;
  1149.                 }
  1150.             }
  1151.         }
  1152.         if (!p) {
  1153.             if (found) {
  1154.                 if (nohang & 1)
  1155.                     return 0;
  1156.                 if (curproc->pid)
  1157.                     TRACE(("Pwaitpid: going to sleep"));
  1158.                 sleep(WAIT_Q, (long)p_waitpid);
  1159.             }
  1160.             else {
  1161.                 DEBUG(("Pwaitpid: no children found"));
  1162.                 return EFILNF;
  1163.             }
  1164.         }
  1165.     } while (!p);
  1166.  
  1167. /* OK, we've found our child */
  1168. /* calculate the return code from the child's exit code and pid */
  1169.     r = (((unsigned long)p->pid) << 16) | (p->wait_cond & 0x0000ffff);
  1170.  
  1171. /* check resource usage */
  1172.     if (rusage) {
  1173.         *rusage++ = p->usrtime + p->chldutime;
  1174.         *rusage = p->systime + p->chldstime;
  1175.     }
  1176.  
  1177. /* avoid adding adopted trace processes usage to the foster parent */
  1178.     if (curproc->pid == p->ppid) {
  1179.     /* add child's resource usage to parent's */
  1180.         if (p->wait_q == TSR_Q || p->wait_q == ZOMBIE_Q) {
  1181.             curproc->chldstime += p->systime + p->chldstime;
  1182.             curproc->chldutime += p->usrtime + p->chldutime;
  1183.         }
  1184.     }
  1185.  
  1186. /* if it was stopped, mark it as having been found and again return */
  1187.     if (p->wait_q == STOP_Q) {
  1188.         p->wait_cond = 0;
  1189.         return r;
  1190.     }
  1191.  
  1192. /* We have to worry about processes which attach themselves to running
  1193.  * processes which they want to trace. We fix things up so that the
  1194.  * second time the signal gets delivered we will go all the way to the
  1195.  * end of this function.
  1196.  */
  1197.      if (p->ptracer && p->ptracer->pid != p->ppid) {
  1198.         if (curproc == p->ptracer) {
  1199.         /* deliver the signal to the tracing process first */
  1200.             TRACE(("Pwaitpid(ptracer): returning status to tracing process"));
  1201.             p->ptracer = NULL;
  1202.             if (p->ppid != -1)
  1203.                 return r;
  1204.         }
  1205.         else {
  1206.         /* Hmmm, the real parent got here first */
  1207.             TRACE(("Pwaitpid(ptracer): returning status to parent process"));
  1208.             p->ppid = -1;
  1209.             return r;
  1210.         }
  1211.     }
  1212.     
  1213. /* if it was a TSR, mark it as having been found and return */
  1214.     if (p->wait_q == TSR_Q) {
  1215.         p->ppid = -1;
  1216.         return r;
  1217.     }
  1218.  
  1219. /* it better have been on the ZOMBIE queue from here on in... */
  1220.     assert(p->wait_q == ZOMBIE_Q);
  1221.     assert(p != curproc);
  1222.  
  1223. /* take the child off both the global and ZOMBIE lists */
  1224.     { short sr = spl7();
  1225.     rm_q(ZOMBIE_Q, p);
  1226.     spl(sr);
  1227.     }
  1228.  
  1229.     if (proclist == p) {
  1230.         proclist = p->gl_next;
  1231.         p->gl_next = 0;
  1232.     }
  1233.     else {
  1234.         q = proclist;
  1235.         while(q && q->gl_next != p)
  1236.             q = q->gl_next;
  1237.         assert(q);
  1238.         q->gl_next = p->gl_next;
  1239.         p->gl_next = 0;
  1240.     }
  1241.  
  1242.     dispose_proc(p);    /* free the PROC structure */
  1243.  
  1244.     return r;
  1245. }
  1246.  
  1247. /* p_wait3: BSD process termination primitive, here to maintain
  1248.  * compatibility with existing binaries.
  1249.  */
  1250. long ARGS_ON_STACK
  1251. p_wait3(nohang, rusage)
  1252.     int nohang;
  1253.     long *rusage;
  1254. {
  1255.     return p_waitpid(-1, nohang, rusage);
  1256. }
  1257.  
  1258. /* p_wait: block until a child has exited, and don't worry about
  1259.    resource stats. this is provided as a convenience, and to maintain
  1260.    compatibility with existing binaries (yes, I'm lazy...). we could
  1261.    make do with Pwaitpid().
  1262.  */
  1263.  
  1264. long ARGS_ON_STACK
  1265. p_wait()
  1266. {
  1267. /*
  1268.  * BEWARE:
  1269.  * POSIX says that wait() should be implemented as
  1270.  * Pwaitpid(-1, 0, (long *)0). Pwait is really not
  1271.  * useful for much at all, but we'll keep it around
  1272.  * for a while (with it's old, crufty semantics)
  1273.  * for backwards compatibility. People implementing
  1274.  * POSIX style libraries should use Pwaitpid even
  1275.  * to implement wait().
  1276.  */
  1277.     return p_wait3(2, (long *)0);
  1278. }
  1279.  
  1280. /*
  1281.  * do_vfork(save): create a duplicate of  the current process. This is
  1282.  * essentially a vfork() algorithm, except that if (save == 1) the
  1283.  * parent's address space is saved, and then restored when the process
  1284.  * is made runnable again. The parent is suspended until either the child
  1285.  * process (the duplicate) exits or does a Pexec which overlays its
  1286.  * memory space.
  1287.  *
  1288.  * "txtsize" is the size of the process' TEXT area, if it has a valid one;
  1289.  * this is part of the second memory region attached (the basepage one)
  1290.  * and need not be saved (we assume processes don't write on their own
  1291.  * code segment)
  1292.  */
  1293.  
  1294. static long
  1295. do_vfork(save)
  1296.     int save;
  1297. {
  1298.     PROC *p;
  1299.     long sigmask;
  1300.     MEMREGION *m, *savemem = 0;
  1301.     long savesize, txtsize;
  1302.     int i, newpid;
  1303.     char *saveplace;
  1304.  
  1305.     p = fork_proc();
  1306.     if (!p) {
  1307.         DEBUG(("do_vfork: couldn't get new PROC struct"));
  1308.         return mint_errno;
  1309.     }
  1310. /* set u:\proc time+date */
  1311.     proctime = timestamp;
  1312.     procdate = datestamp;
  1313.  
  1314. /*
  1315.  * maybe save the parent's address space
  1316.  */
  1317.     txtsize = p->txtsize;
  1318.  
  1319.     if (save) {
  1320.         TRACE(("do_vfork: saving parent"));
  1321.         savesize = memused(curproc) - txtsize;
  1322.         if (!txtsize && (p->base->p_flags & F_SHTEXT)) {
  1323.             for (i = 0; i < curproc->num_reg; i++) {
  1324.                 m = curproc->mem[i];
  1325.                 if (m && (m->mflags & M_SHTEXT)) {
  1326.                     savesize -= m->len;
  1327.                     break;
  1328.                 }
  1329.             }
  1330.         }
  1331.         assert(savesize >= 0);
  1332.  
  1333.         saveplace = (char *)alloc_region(alt, savesize, PROT_P);
  1334.         if (!saveplace)
  1335.             saveplace = (char *)alloc_region(core, savesize, PROT_P);
  1336.  
  1337.         if (!saveplace) {
  1338.             DEBUG(("do_vfork: can't save parent's memory"));
  1339.             p->ppid = 0;        /* abandon the child */
  1340.             post_sig(p, SIGKILL);    /* then kill it */
  1341.             p->ctxt[CURRENT].pc = (long)check_sigs;
  1342.             p->ctxt[CURRENT].sr |= 0x2000; /* use supervisor stack */
  1343. #if 0    /* stack set up in fork_proc() */
  1344.             p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
  1345. #endif
  1346.             p->pri = MAX_NICE+1;
  1347.             run_next(p, 1);
  1348.             yield();
  1349.             return ENSMEM;
  1350.         }
  1351.         savemem = addr2mem((virtaddr)saveplace);
  1352.         assert(savemem);
  1353.         savemem->mflags |= M_FSAVED;
  1354.         for (i = 0; i < curproc->num_reg; i++) {
  1355.             m = curproc->mem[i];
  1356.             if (m && !(m->mflags & (M_SEEN|M_FSAVED|M_SHTEXT))) {
  1357.                 m->mflags |= M_SEEN; /* save links only once */
  1358.  
  1359.                 if (i != 1 || txtsize == 0) {
  1360.                     quickmove(saveplace, (char *)m->loc, m->len);
  1361.                     saveplace += m->len;
  1362.                 }
  1363.                 else {
  1364.                     quickmove(saveplace, (char *)m->loc+txtsize,
  1365.                     m->len - txtsize);
  1366.                     saveplace += m->len - txtsize;
  1367.                 }
  1368.             }
  1369.         }
  1370.         for (i = 0; i < curproc->num_reg; i++) {
  1371.             if (curproc->mem[i])
  1372.                 curproc->mem[i]->mflags &= ~M_SEEN;
  1373.         }
  1374.     }
  1375.                 
  1376.     p->ctxt[CURRENT] = p->ctxt[SYSCALL];
  1377.     p->ctxt[CURRENT].regs[0] = 0;    /* child returns a 0 from call */
  1378.     p->ctxt[CURRENT].sr &= ~(0x2000); /* child must be in user mode */
  1379. #if 0        /* set up in fork_proc() */
  1380.     p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
  1381. #endif
  1382.  
  1383. /* watch out for job control signals, since our parent can never wake
  1384.  * up to respond to them. solution: block them; exec_region (in mem.c)
  1385.  * clears the signal mask, so an exec() will unblock them.
  1386.  */
  1387.     p->sigmask |= (1L << SIGTSTP) | (1L << SIGTTIN) | (1L << SIGTTOU);
  1388.  
  1389.     TRACE(("do_vfork: parent going to sleep, wait_cond == %lx",
  1390.         (long)p));
  1391.  
  1392. /* WARNING: This sleep() must absolutely not wake up until the child
  1393.  * has released the memory space correctly. That's why we mask off
  1394.  * all signals.
  1395.  */
  1396.     sigmask = curproc->sigmask;
  1397.     curproc->sigmask = ~(((unsigned long)1 << SIGKILL) | 1);
  1398.  
  1399.     { short sr = spl7();
  1400.     add_q(READY_Q, p);        /* put it on the ready queue */
  1401.     sleep(WAIT_Q, (long)p);            /* while we wait for it */
  1402.     spl(sr);
  1403.     }
  1404.     TRACE(("do_vfork: parent waking up"));
  1405.  
  1406.     if (save) {
  1407.         fork_restore(curproc, 0L);
  1408.     }
  1409.     curproc->sigmask = sigmask;
  1410. /* note that the PROC structure pointed to by p may be freed during
  1411.  * the check_sigs call!
  1412.  */
  1413.     newpid = p->pid;
  1414.     check_sigs();    /* did we get any signals while sleeping? */
  1415.     return newpid;
  1416. }
  1417.  
  1418. /*
  1419.  * fork_restore(p): restore process memory after a blocking fork
  1420.  */
  1421.  
  1422. void fork_restore(p, savemem)
  1423. PROC *p;
  1424. MEMREGION *savemem;
  1425. {
  1426.     MEMREGION *m;
  1427.     long txtsize = p->txtsize;
  1428.     char *saveplace;
  1429.     int i;
  1430.     extern int no_mem_prot;
  1431.  
  1432.     if (!savemem) {
  1433.         for (i = 0; i < p->num_reg; i++) {
  1434.             m = p->mem[i];
  1435.             if (m && (m->mflags & M_FSAVED)) {
  1436.                 savemem = m;
  1437.                 break;
  1438.             }
  1439.         }
  1440.         if (!savemem)
  1441.             return;
  1442.     }
  1443.     saveplace = (char *)savemem->loc;
  1444.  
  1445.     TRACE(("do_vfork: parent restoring memory"));
  1446. #if 1
  1447.     if (p != curproc && !no_mem_prot)
  1448. /* memprot doesn't like it?  try p's mmu context... */
  1449.         set_mmu (p->ctxt[CURRENT].crp, p->ctxt[CURRENT].tc);
  1450. #endif
  1451.     for (i = 0; i < p->num_reg; i++) {
  1452.         m = p->mem[i];
  1453.         if (m && !(m->mflags & (M_SEEN|M_FSAVED|M_SHTEXT))) {
  1454.             m->mflags |= M_SEEN;
  1455.             if (i != 1 || txtsize == 0) {
  1456.                 quickmove((char *)m->loc, saveplace, m->len);
  1457.                 saveplace += m->len;
  1458.             }
  1459.             else {
  1460.                 quickmove((char *)m->loc+txtsize, saveplace,
  1461.                 m->len - txtsize);
  1462.                 saveplace += m->len - txtsize;
  1463.             }
  1464.         }
  1465.     }
  1466.     for (i = 0; i < p->num_reg; i++) {
  1467.         if (p->mem[i])
  1468.             p->mem[i]->mflags &= ~M_SEEN;
  1469.     }
  1470. #if 1
  1471.     if (p != curproc && !no_mem_prot)
  1472.         set_mmu (curproc->ctxt[CURRENT].crp, curproc->ctxt[CURRENT].tc);
  1473. #endif
  1474.     detach_region(p, savemem);
  1475. }
  1476.  
  1477. /*
  1478.  * here are the interfaces that the user sees. Pvfork() doesn't save
  1479.  * the child's address space; Pfork() does. Someday Pfork() should
  1480.  * allow asynchronous execution of both child and parent, but this
  1481.  * will do for now.
  1482.  */
  1483.  
  1484. long ARGS_ON_STACK
  1485. p_vfork()
  1486. {
  1487.     return do_vfork(0);
  1488. }
  1489.  
  1490. long ARGS_ON_STACK
  1491. p_fork()
  1492. {
  1493.     return do_vfork(1);
  1494. }
  1495.